package com.haidechizi.doublecache.cachemanager;

import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 自定义内存缓存
 *
 * @param <T>
 */
public class MemoryCacheManager<T> {

    private Map<String, CacheData<T>> cacheMap = new ConcurrentHashMap<>();

    private ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1);

    public MemoryCacheManager() {
        cleanInvalidCache();
    }

    public T get(String cacheKey) {
        CacheData<T> cacheData = cacheMap.get(cacheKey);
        if (cacheData == null) {
            return null;
        }
        if (cacheData.expire()) {
            // 数据已过期
            cacheMap.remove(cacheKey);
            return null;
        }
        return cacheData.data;
    }

    /**
     * @param cacheKey 缓存key
     * @param data     缓存数据
     * @param expire   过期时间：-1表示不过期
     */
    public void set(String cacheKey, T data, int expire) {
        CacheData<T> cacheData = new CacheData<>(data, expire);
        cacheMap.put(cacheKey, cacheData);
    }

    /**
     * 批量设置缓存
     *
     * @param cacheValues
     * @param expire
     */
    public void mset(Map<String, T> cacheValues, int expire) {
        for (Map.Entry<String, T> entry : cacheValues.entrySet()) {
            CacheData<T> cacheData = new CacheData<>(entry.getValue(), expire);
            cacheMap.put(entry.getKey(), cacheData);
        }
    }

    /**
     * 更加key清空缓存
     *
     * @param cacheKey
     */
    public void removeCache(String cacheKey) {
        cacheMap.remove(cacheKey);
    }

    /**
     * 清空缓存
     */
    public void clearCache() {
        cacheMap.clear();
    }

    private static class CacheData<T> {

        private T data;
        private long time;
        private long expireTime;
        private int expire;

        public CacheData(T data, int expire) {
            this.data = data;
            this.expire = expire;
            // 当前的毫秒值
            this.time = System.currentTimeMillis();
            if (expire == -1) {
                return;
            }
            if (expire <= 0) {
                throw new RuntimeException("过期时间设置错误");
            }
            this.expireTime = time + expire * 1000;
        }


        public boolean expire() {
            // 不过期
            if (this.expire == -1) {
                return false;
            }
            // 判断数据是否过期
            if (this.expireTime < System.currentTimeMillis()) {
                return true;
            }
            return false;
        }
    }

    private void cleanInvalidCache() {
        executorService.scheduleAtFixedRate(() -> {
            Iterator<Map.Entry<String, CacheData<T>>> iterator = cacheMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, CacheData<T>> entry = iterator.next();
                if (entry.getValue().expire()) {
                    iterator.remove();
                }
            }
        }, 5, 5, TimeUnit.SECONDS);
    }
}
